package models

import (
	"os"
	"path"
	"time"

	"github.com/Unknwon/com"
	"github.com/astaxie/beego/orm"
	_ "github.com/mattn/go-sqlite3"
	"strconv"
	"fmt"
	"strings"
)

const (
	_DB_NAME        = "data/beeblog.db"
	_SQLITE3_DRIVER = "sqlite3"
)

type Category struct {
	Id              int64
	Title           string
	Created         time.Time `orm:"index"`
	Views           int64     `orm:"index"`
	TopicTime       time.Time `orm:"index"`
	TopicCount      int64
	TopicLastUserId int64
}

type Topic struct {
	Id              int64
	Uid             int64
	Title           string
	Content         string    `orm:"size(5000)"`
	Category        string
	Attachment      string
	Created         time.Time `orm:"index"`
	Updated         time.Time `orm:"index"`
	Views           int64     `orm:"index"`
	Author          string
	Replytime       time.Time `orm:"index"`
	ReplyCount      int64
	ReplyLastUserId int64
	Lables			string
}

type Comment struct {
	Id      int64
	Tid     int64
	Name    string
	Content string    `orm:"size(1000)"`
	Created time.Time `orm:"index"`
}

func RegisterDB() {
	if !com.IsExist(_DB_NAME) {
		os.MkdirAll(path.Dir(_DB_NAME), os.ModePerm)
		os.Create(_DB_NAME)
	}

	orm.RegisterModel(new(Category), new(Topic), new(Comment))
	orm.RegisterDriver(_SQLITE3_DRIVER, orm.DRSqlite)
	orm.RegisterDataBase("default", _SQLITE3_DRIVER, _DB_NAME, 10)
}

func AddCategory(name string) error {
	o := orm.NewOrm()
	cate := &Category{Title: name, Created: time.Now(), TopicTime: time.Now()}
	//err := o.Read(cate)
	qs := o.QueryTable("category")
	err := qs.Filter("title", name).One(cate)
	if err == nil {
		return err
	}
	_, err = o.Insert(cate)
	if err != nil {
		return err
	}
	return nil
}

func GetAllCategories() ([]*Category, error) {
	o := orm.NewOrm()
	cates := make([]*Category, 0)
	qs := o.QueryTable("category")
	_, err := qs.All(&cates)
	return cates, err
}

func DelCategory(id int64) error {
	o := orm.NewOrm()
	cate := Category{Id: id}

	_, err := o.Delete(&cate)
	if err != nil {
		return err
	}
	return nil
}

func UpdateTopic(tid, title, content,category ,lables string) error {
	o := orm.NewOrm()
	newLables := "$"+ strings.Join(strings.Split(lables," "),"#$")+"#"
	Tid, err := strconv.ParseInt(tid, 10, 64)
	if err != nil {
		return nil
	}
	topic := &Topic{Id: Tid, Title: title, Content: content, Created: time.Now(), Updated: time.Now(), Replytime: time.Now()}
	//fmt.Println(topic)
	qs := o.QueryTable("topic")
	err = qs.Filter("id", Tid).One(topic)
	if err != nil {
		return err
	}
	oldCate := topic.Category
	topic.Title = title
	topic.Content = content
	topic.Updated = time.Now()
	topic.Category = category
	topic.Lables = newLables
	fmt.Println(topic.Created)
	fmt.Println(topic.Updated)
	_, err = o.Update(topic)
	if err != nil {
		return err
	}
	//更新category
	cate := &Category{Title:oldCate}
	err =o.Read(cate,"Title")
	if err == nil{
		categorys,err := QureyDecAllTopics(oldCate)
		if err ==nil{
			count := int64(len(categorys))
			cate.TopicCount = count
			o.Update(cate)
		}
	}
	cate = &Category{Title:category}
	err =o.Read(cate,"Title")
	if err == nil{
		categorys,err := QureyDecAllTopics(category)
		if err ==nil{
			count := int64(len(categorys))
			cate.TopicCount = count
			o.Update(cate)
		}
	}
	return nil
}

func AddTopic(title, content, category ,lables string) error {
	o := orm.NewOrm()
	newLables := "$"+ strings.Join(strings.Split(lables," "),"#$")+"#"

	topic := &Topic{Title: title, Content: content, Category: category, Created: time.Now(), Updated: time.Now(), Replytime: time.Now(),Lables:newLables}
	_, err := o.Insert(topic)
	if err != nil {
		return err
	}

	cate := &Category{Title:category}
	qs := o.QueryTable("category")
	err = qs.Filter("title",category).One(cate)
	if err == nil{
		categorys,err := QureyDecAllTopics(category)
		if err ==nil{
			count := int64(len(categorys))
			cate.TopicCount = count
			o.Update(cate)
		}
	}

	return nil
}

func QureyTopic(tid string) (Topic, error) {
	o := orm.NewOrm()
	var topic Topic
	Tid, err := strconv.ParseInt(tid, 10, 64)
	if err != nil {
		return topic, err
	}

	err = o.Raw("select * from topic where Id = ?", Tid).QueryRow(&topic)
	topic.Views++
	_, err = o.Update(&topic)
	topic.Lables = strings.Replace(strings.Replace(
		topic.Lables, "#", " ", -1), "$", "", -1)
	return topic, err
}

func QureyAllTopics() ([]*Topic, error) {
	o := orm.NewOrm()
	topics := make([]*Topic, 0)
	qs := o.QueryTable("topic")
	_, err := qs.All(&topics)
	return topics, err
}

func QureyDecAllTopics(category string) ([]*Topic, error) {
	o := orm.NewOrm()
	topics := make([]*Topic, 0)
	qs := o.QueryTable("topic")
	if len(category)>0{
		qs = qs.Filter("category" ,category)
	}
	_, err := qs.OrderBy("-created").All(&topics)
	return topics, err
}

func GetDecAllTopics(category ,lable string) ([]*Topic, error) {
	o := orm.NewOrm()
	topics := make([]*Topic, 0)
	qs := o.QueryTable("topic")
	if len(category)>0{
		qs = qs.Filter("category" ,category)
	}
	if len(lable)>0{
		qs = qs.Filter("lables__contains","$"+lable+"#")
	}
	_, err := qs.OrderBy("-created").All(&topics)
	return topics, err
}

func DeleteTopic(tid,category string) error {
	o := orm.NewOrm()
	Tid, err := strconv.ParseInt(tid, 10, 64)
	if err != nil {
		return err
	}
	topic := &Topic{Id: Tid}
	_, err = o.Delete(topic)
	if err != nil {
		return err
	}

	cate := &Category{Title:category}
	qs := o.QueryTable("category")
	err = qs.Filter("title",category).One(cate)
	if err == nil{
		categorys,err := QureyDecAllTopics(category)
		if err ==nil{
			count := int64(len(categorys))
			cate.TopicCount = count
			o.Update(cate)
		}
	}

	return nil
}

func AddReply(tid, name, content string) error {
	o := orm.NewOrm()
	Tida, err := strconv.ParseInt(tid, 10, 64)
	if err != nil {
		return err
	}

	comment := &Comment{Tid: Tida, Name: name, Content: content, Created: time.Now()}
	_, err = o.Insert(comment)
	if err != nil {
		return err
	}

	topic := new(Topic)
	qs := o.QueryTable("topic")
	err = qs.Filter("id", Tida).One(topic)
	if err != nil {
		return err
	}
	topic.ReplyCount++
	topic.Replytime = time.Now()
	_, err = o.Update(topic)
	if err != nil {
		return err
	}
	return nil

}

func GetAllReply(tid string)([]*Comment,error){
	o := orm.NewOrm()
	Tid, err := strconv.ParseInt(tid, 10, 64)
	if err != nil {
		return nil,err
	}
	var reply []*Comment = make([]*Comment,0)
	qs := o.QueryTable("comment")
	_,err = qs.Filter("tid",Tid).All(&reply)
	if err != nil {
		return nil,err
	}
	return reply,nil
}

func DeleteReply(tid,id string)error{
	o := orm.NewOrm()
	Ida, err := strconv.ParseInt(id, 10, 64)
	Tida, err := strconv.ParseInt(tid, 10, 64)
	if err != nil {
		return err
	}
	reply := Comment{Id:Ida}

	_,err = o.Delete(&reply)
	if err != nil {
		return err
	}

	topic := new(Topic)
	qs := o.QueryTable("topic")
	err = qs.Filter("id", Tida).One(topic)
	if err != nil {
		return err
	}
	//这边有个bug，不是精确的数值，会抛出index out of range 异常，改成上面那中精确的就好了，获得全部的评论
	topic.ReplyCount--
	var replys []*Comment = make([]*Comment,0)
	qss := o.QueryTable("comment")
	_,err = qss.OrderBy("-created").Filter("tid",Tida).All(&replys)
	if err== nil{
		topic.Replytime = replys[0].Created
	}
	_, err = o.Update(topic)
	if err != nil {
		return err
	}
	return nil
}
